#include "mytest.h"

//------------------------------------------------------------
static void test_bit_field_table()
{
    test_begin("test_bit_field");

    assert(BitCnt12[0x000]==0);
    assert(BitCnt12[0x111]==3);
    assert(BitCnt12[0x777]==9);
    assert(BitCnt12[0xfff]==12);

    assert(Lsb12[0x333]==0);
    assert(Lsb12[0x332]==1);
    assert(Lsb12[0x331]==0);
    assert(Lsb12[0x330]==4);
    assert(Lsb12[0x300]==8);
    assert(Lsb12[0x338]==3);

    for (int i=0; i<=0xFFF; i++)
    {
        assert(Dir[Lsb12[i]]==LsDir[i]);
    }

    test_end();
}

//------------------------------------------------------------
static void test_board()
{
    test_begin("test_board");

    board_t b[1];

    //------------------------------
    board_clear(b);

    for (int z=0; z<256; z++)
    {
        if (POS_IS_OB(z))
        {
            assert(b->sq[z]==OB);
        }
        else
        {
            assert(b->sq[z]==0);
        }
    }
    for (int k=0;k<8;k++)
    {
        assert(b->h[C0][k]==0);
        assert(b->h[C1][k]==0);
    }
    assert(b->h32[C0]==0);
    assert(b->h32[C1]==0);

    //------------------------------
    // P1 *  *  *  *  *  *  *  *  *
    // P2 *  *  *  *  *  *  *  *  *
    // P3 *  *  *  *  *  *  *  *  *
    // P4 *  *  *  *  *  *  *  *  *
    // P5 *  *  *  * -KA *  *  *  *
    // P6 *  *  *  * +HI *  *  *  *
    // P7 *  * +FU *  *  *  *  *  *
    // P8 * +KE *  *  *  *  *  *  *
    // P9 *  *  *  *  *  *  *  *  *
    // P-00FU00FU00FU00FU00FF00KA00KA

    b->sq[0x77] = FU0;
    b->sq[0x55] = KA1;
    b->sq[0x56] = HI0;
    b->sq[0x88] = KE0;
    b->h[C1][FU] = 5;
    b->h[C1][KA] = 2;

    board_build(b);

    assert(b->sq[0x77]==FU0);
    assert(b->sq[0x55]==KA1);
    assert(b->sq[0x56]==HI0);
    assert(b->sq[0x88]==KE0);

    assert(b->ef[C0][0x96]==(NNW_b|W_2b));
    assert(b->ef[C0][0x86]==(W_2b));
    assert(b->ef[C0][0x76]==(NNE_b|N_b|W_2b));
    assert(b->ef[C1][0x76]==0);
    assert(b->ef[C0][0x77]==0);
    assert(b->ef[C1][0x77]==(SW_2b));
    assert(b->ef[C0][0x78]==0);
    assert(b->ef[C1][0x78]==0);

    assert(b->ef[C0][0x55]==(N_2b));
    assert(b->ef[C0][0x57]==(S_2b));
    assert(b->ef[C0][0x58]==(S_2b));
    assert(b->ef[C0][0x59]==(S_2b));
    assert(b->ef[C1][0x44]==(NE_2b));
    assert(b->ef[C1][0x33]==(NE_2b));
    assert(b->ef[C1][0x22]==(NE_2b));
    assert(b->ef[C1][0x11]==(NE_2b));
    assert(b->ef[C1][0x00]==(NE_2b));
    assert(b->ef[C1][0x64]==(NW_2b));
    assert(b->ef[C1][0x73]==(NW_2b));
    assert(b->ef[C1][0x82]==(NW_2b));
    assert(b->ef[C1][0x91]==(NW_2b));
    assert(b->ef[C1][0xa0]==(NW_2b));
    assert(b->ef[C1][0x66]==(SW_2b));
    assert(b->ef[C1][0x46]==(SE_2b));
    assert(b->ef[C1][0x37]==(SE_2b));
    assert(b->ef[C1][0x28]==(SE_2b));
    assert(b->ef[C1][0x19]==(SE_2b));
    assert(b->ef[C1][0x0a]==(SE_2b));

    for (int k=0;k<8;k++)
    {
        switch (k)
        {
            case FU:
                assert(b->h[C0][k]==0);
                assert(b->h[C1][k]==5);
                break;
            case KA:
                assert(b->h[C0][k]==0);
                assert(b->h[C1][k]==2);
                break;
            default:
                assert(b->h[C0][k]==0);
                assert(b->h[C1][k]==0);
                break;
        }
    }
    assert(b->h32[C0]==0);
    assert(b->h32[C1]==0x05000020);

    // backup effect table
    int ef0[256],ef1[256];
    for (int i=0;i<256;i++)
    {
        ef0[i] = b->ef[C0][i];
        ef1[i] = b->ef[C1][i];
    }

    //------------------------------
    // --> move +7776FU
    // P1 *  *  *  *  *  *  *  *  *
    // P2 *  *  *  *  *  *  *  *  *
    // P3 *  *  *  *  *  *  *  *  *
    // P4 *  *  *  *  *  *  *  *  *
    // P5 *  *  *  * -KA *  *  *  *
    // P6 *  * +FU * +HI *  *  *  *
    // P7 *  *  *  *  *  *  *  *  *
    // P8 * +KE *  *  *  *  *  *  *
    // P9 *  *  *  *  *  *  *  *  *

    int move=MOVE(0x77,0x76,FU);
    move_do(b,move);

    assert(b->sq[0x77]==0);
    assert(b->sq[0x76]==FU0);
    for (int i=0;i<256;i++)
    {
        switch (i)
        {
            case 0xa6:
                assert(b->ef[C0][i]==0);
                assert(b->ef[C1][i]==ef1[i]);
                break;
            case 0x96:
                assert(b->ef[C0][i]==NNW_b);
                assert(b->ef[C1][i]==ef1[i]);
                break;
            case 0x86:
                assert(b->ef[C0][i]==0);
                assert(b->ef[C1][i]==ef1[i]);
                break;
            case 0x75:
                assert(b->ef[C0][i]==N_b);
                assert(b->ef[C1][i]==ef1[i]);
               break;
            case 0x76:
                assert(b->ef[C0][i]==(NNE_b|W_2b));
                assert(b->ef[C1][i]==ef1[i]);
                break;
            case 0x77:
                assert(b->ef[C0][i]==ef0[i]);
                assert(b->ef[C1][i]==SW_2b);
                break;
            case 0x88:
                assert(b->ef[C0][i]==ef0[i]);
                assert(b->ef[C1][i]==SW_2b);
                break;
            default:
                assert(b->ef[C0][i]==ef0[i]);
                assert(b->ef[C1][i]==ef1[i]);
                break;
        }

    }

    //------------------------------
    // --> undo move +7776FU

    int undo=move_undo(b);
    //printf("%x, %x, %x\n",UNDO_MOVE(undo),UNDO_PIECE(undo),UNDO_CAPT(undo));
    assert(undo==UNDO(move,FU0,0));

    for (int i=0;i<256;i++)
    {
        //printf("%x = %x, %x\n",i,b->ef[C0][i],b->ef[C1][i]);
        assert(b->ef[C0][i]==ef0[i]);
        assert(b->ef[C1][i]==ef1[i]);
    }
    test_end();
}

//------------------------------------------------------------
static void board_test_move_and_unmove()
{
    static int moves1[]={
        MOVE(0x77,0x76,FU),MOVE(0x33,0x34,FU),
        MOVE(0x88,0x22,UM),MOVE(0x31,0x22,GI),
        MOVE(0x00,0x55,KA),MOVE(0x22,0x33,GI),
        MOVE(0x55,0x33,UM),MOVE(0x21,0x33,KE),
        0
    };
    static int *moves[]={moves1,NULL};

    test_begin("board_test_move_and_unmove");

    board_t b[1];
    board_hirate(b);
    assert(board_health_check(b));
    test_ok();

    for (int j=0;moves[j]!=NULL;j++)
    {
        for (int i=0;moves[j][i]!=0;i++)
        {
            move_do(b,moves[j][i]);
            assert(board_health_check(b));
            test_ok();
        }
        while (b->counter>0)
        {
            move_undo(b);
            assert(board_health_check(b));
            test_ok();
        }
    }

    test_end();
}

//------------------------------------------------------------
void board_test_all()
{
    test_begin("board_test_all");

    test_bit_field_table();
    test_board();
    board_test_move_and_unmove();

    test_end();
}
